package cz.cuni.mff.ufal.volk.utils;

import java.io.ByteArrayInputStream;
import java.io.Serializable;
import java.util.Arrays;

/**
 * A read-only wrapper over byte array.
 *
 * @author Bartłomiej Etenkowski
 */
public class ByteArray implements Serializable {

  private static final long serialVersionUID = -8221378544532362637L;

  /**
   * Constructs a new read-only byte array.
   * @param b underlying byte array. A copy of the array is used so the array passed
   *        as the parameter can be later modified.
   * @throws NullPointerException if the {@code b} parameter is {@code null}
   */
  public ByteArray(byte[] b) {
    b.getClass();
    underlyingArray = Arrays.copyOf(b, b.length);
  }

  private final byte[] underlyingArray;

  /**
   * Copies the specified range of the underlying array into a new array.
   * @param  from the initial index of the range to be copied, inclusively
   * @param  to the final index of the range to be copied, exclusively
   * @return a new array containing the specified range of the underlying array
   * @throws IndexOutOfBoundsException if the specified range is incorrect (from or to < 0
   *         or from or to >= {@link #size()})
   * @throws IllegalArgumentException if to < from
   */
  public byte[] copy(int from, int to) {
    return Arrays.copyOfRange(underlyingArray, from, to);
  }

  /**
   * Copies the underlying array into the specified buffer.
   * @param  buffer the buffer
   * @param  offset the offset in the buffer
   * @throws IndexOutOfBoundsException if offset < 0 or offset + {@link #size()} > {@code buffer.size()}
   */
  public void copyTo(byte[] buffer, int offset) {
    copyTo(buffer, offset, 0, size());
  }

  /**
   * Copies the specified range of the underlying array into the specified buffer.
   * @param  buffer the buffer
   * @param  offset the offset in the buffer
   * @param  from the initial index of the range to be copied, inclusively
   * @param  to the final index of the range to be copied, exclusively
   * @throws NullPointerException if the buffer parameter is {@code null}
   * @throws IndexOutOfBoundsException if from or to < 0, from or to > {@link #size()}, offset
   *         < 0 or offset + to - from > {@code buffer.size()}
   * @throws IllegalArgumentException if to < from
   */
  public void copyTo(byte[] buffer, int offset, int from, int to) {
    buffer.getClass();
    int length = to - from;
    for (int i = 0; i < length; i++) {
      buffer[offset + i] = underlyingArray[from + i];
    }
  }

  /**
   * Returns the number of elements in the array.
   * @return the number of elements in the array
   */
  public int size() {
    return underlyingArray.length;
  }

  /**
   * Returns the byte stored under the specified index.
   * @param  index index of byte to return
   * @return the byte stored under the specified index
   * @throws IndexOutOfBoundsException if the index is out of range
   */
  public byte get(int index) {
    return underlyingArray[index];
  }

  /**
   * Returns an input stream.
   * @return an input stream
   */
  public ByteArrayInputStream getInputStream() {
    return new ByteArrayInputStream(underlyingArray);
  }
}
